package org.codefilarete.stalactite.query.model.operator;

import org.codefilarete.stalactite.query.model.UnitaryOperator;

/**
 * Represents a like comparison.
 * Options to create a "startsWith" and "endsWith" are provided.
 * 
 * @author Guillaume Mary
 */
public class Like<V> extends UnitaryOperator<V> {
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "starts with" criterion.
	 * @param value something that looks like a String (may contain '%' characters)
	 * @return a new instance of {@link Like} that is a "starts with" criterion 
	 */
	public static <V extends CharSequence> Like<V> startsWith(V value) {
		return new Like<>(value, false, true);
	}
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "starts with" criterion without value for now : must be set
	 * later with {@link super#setValue(Object)}
	 * @return a new instance of {@link Like} that is a "starts with" criterion 
	 */
	public static <V extends CharSequence> Like<V> startsWith() {
		return new Like<>(false, true);
	}
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "ends with" criterion.
	 * @param value something that looks like a String (may contain '%' characters)
	 * @return a new instance of {@link Like} that is a "ends with" criterion 
	 */
	public static <V extends CharSequence> Like<V> endsWith(V value) {
		return new Like<>(value, true, false);
	}
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "ends with" criterion without value for now : must be set
	 * later with {@link super#setValue(Object)}
	 * @return a new instance of {@link Like} that is a "ends with" criterion 
	 */
	public static <V extends CharSequence> Like<V> endsWith() {
		return new Like<>(true, false);
	}
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "contains" criterion.
	 * @param value something that looks like a String (may contain '%' characters)
	 * @return a new instance of {@link Like} that is a "contains" criterion 
	 */
	public static <V extends CharSequence> Like<V> contains(V value) {
		return new Like<>(value, true, true);
	}
	
	/**
	 * Shortcut that builds a {@link Like} instance for a "contains" criterion without value for now : must be set
	 * later with {@link super#setValue(Object)}
	 * @return a new instance of {@link Like} that is a "contains" criterion 
	 */
	public static <V extends CharSequence> Like<V> contains() {
		return new Like<>(true, true);
	}
	
	private final boolean leadingStar;
	private final boolean endingStar;
	
	/**
	 * Constructor for "startsWith" and "endsWith" operator without value for now : must be set later with
	 * {@link super#setValue(Object)}
	 */
	public Like() {
		this(false, false);
	}
	
	/**
	 * Constructor for "startsWith" and "endsWith" operator without value for now : must be set later with
	 * {@link super#setValue(Object)}
	 * 
	 * @param leadingStar true to add a leading generic '%' character
	 * @param endingStar true to add a ending generic '%' character
	 */
	public Like(boolean leadingStar, boolean endingStar) {
		this.leadingStar = leadingStar;
		this.endingStar = endingStar;
	}
	
	/**
	 * Basic constructor
	 * @param value something that looks like a String, may contain '%' characters
	 */
	public Like(V value) {
		this(value, false, false);
	}
	
	/**
	 * Constructor for "startsWith" and "endsWith" operator
	 * @param value something that looks like a String, may contain '%' characters
	 * @param leadingStar true to add a leading generic '%' character
	 * @param endingStar true to add a ending generic '%' character
	 */
	public Like(V value, boolean leadingStar, boolean endingStar) {
		super(value);
		this.leadingStar = leadingStar;
		this.endingStar = endingStar;
	}
	
	public LikeIgnoreCase<V> ignoringCase() {
		return new LikeIgnoreCase<>(this);
	}
	
	public boolean withLeadingStar() {
		return leadingStar;
	}
	
	public boolean withEndingStar() {
		return endingStar;
	}
}
